#include "IO.h"
#include "global.h"
#include "read.h"
#include <cstdio>
#include <cstring>
#include <vector>

int lstreq[MAX_OBJECT_NUM];
double readpred[MAX_OBJECT_NUM],powd[MAX_T+EXTRA_TIME];
void request_init(int request_id,int object_id)
{
    if(Round==1){
        num_read_for_gather[object[object_id].tag][timestamp]++;
        object[object_id].requests.push_back(request_id);
    }
    if(Round==2){
        object[object_id].it++;
    }
    request[request_id].burntime=timestamp;
    request[request_id].object_id = object_id;
    request[request_id].prev_id = object[object_id].last_request_point;
    object[object_id].last_request_point = request_id;

    request[request_id].remain=object[object_id].size;
    memset(request[request_id].is_done,true,sizeof(request[request_id].is_done));
    for(int j=1;j<=object[object_id].size;j++) request[request_id].is_done[j] = false;
    request[request_id].isbusy=false;
    if(shouldbusy[object_id]) bebusy(request_id);

    if(lstreq[object_id]!=timestamp)
        readpred[object_id]*=powd[timestamp-lstreq[object_id]],
        lstreq[object_id]=timestamp;
    readpred[object_id]+=1-decayrate;
}

int lstvis[MAX_OBJECT_NUM][MAX_OBJECT_SIZE];
bool single_update(int d,int curtime,int &usedtok,int &point,int &token)
{
	int thistok=max((int)ceil(token*0.8),16);

	if(usedtok+thistok>G) return false;
	int object_id=disk[d][point],num=unit_num[d][point];
    if(object_id) lstvis[object_id][num]=max(lstvis[object_id][num],curtime);

	token=thistok;usedtok+=token;
	point=point%V+1;

	return true;
}
void Update_instep(int d,const DiskPoint &point)
{
	int pos=point.pos,token=point.pretoken;
	for(int t=1;t<CYCLE;t++)
	{
		int usedtok=0;
		while(single_update(d,timestamp+t,usedtok,pos,token));
	}
}
void readinit()
{
	memset(lstvis,0,sizeof(lstvis));
	memset(lstreq,0,sizeof(lstreq));
	memset(readpred,0,sizeof(readpred));

	memset(shouldbusy,0,sizeof(shouldbusy));
    shouldbusy[0]=1;
    
	powd[0]=1;
	for(int i=1;i<T+EXTRA_TIME;i++) powd[i]=powd[i-1]*decayrate;
}
Decider decider;
void read_action(int round, int time)
{
    if(time==1) readinit();
    int n_read;
    int request_id, object_id;
    if (round == 1) {
        n_read=getint();// scanf("%d", &n_read);
        n_reads[time] = n_read;
    } else {
        n_read = n_reads[time];
    }

    int n_busy = n_read;
    vector<int> reqs(n_read + 1);
    for (int i = 1; i <= n_read; i++) {
        if (round == 1) {
            request_id=getint();object_id=getint();
            // scanf("%d%d", &request_id, &object_id);
            read_datas[time].emplace_back(request_id, object_id);
        } else {
            const auto& read_tuple = read_datas[time].at(i - 1);
            request_id = get<0>(read_tuple);
            object_id = get<1>(read_tuple);
        }
        request_init(request_id,object_id);

        reqs[i] = request_id;
    }
    while(!Busy_intime[timestamp].empty())
        bebusy(Busy_intime[timestamp].front()),Busy_intime[timestamp].pop();

    static int jmpcount=0;
    if(time==1) jmpcount=0;
	for(int i=1;i<=N;i++)
	{
		for(int pointid=0;pointid<2;pointid++)
        {
            int usedtok=0;
            // if(round == 1)
            bool readjmp=((time+(CYCLE/2))%CYCLE==0);
            if(readjmp)
            {
                // if(round == 1)
				int st=decider.decide(i,pointid);
                // fprintf(stderr,"%d\n",timestamp);
                
				if(disk_point[i][pointid].dis_tox(st)+64<=G)
				{
					while(disk_point[i][pointid].pos!=st) Pass(disk_point[i][pointid],usedtok);
					while(Read(i,disk_point[i][pointid],usedtok));
					if(Round !=2) putchar('#');
				}
				else Jump(disk_point[i][pointid],st),jmpcount++;
				if(Round !=2) putchar('\n');
            }
            else
            {
                while(Read(i,disk_point[i][pointid],usedtok));
				if(Round !=2) putchar('#'),putchar('\n');
            }
        }
    }
    if(timestamp%1800==0) fprintf(stderr,"%d %d %lf \n",timestamp,jmpcount,20.0*timestamp/jmpcount);
    DoneReport();
    BusyReport();
    if(Round !=2) fflush(stdout);
}